﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Microsoft.Xna.Framework;

namespace AL.Doodled
{
    #region enums
    public enum XAlignment
    {
        Left,
        Right
    }

    public enum YAlignment
    {
        Top,
        Bottom
    }

    public enum Measure
    {
        Pixels,
        Percent
    }
    #endregion

    /// <summary>
    /// The widget class is the abstract base class
    /// for all the engines widgets.
    /// </summary>
    public abstract class Widget : IXMLSupported
    {
        #region fields
        private Style style;
        #endregion

        #region properties
        /// <summary>
        /// The size of the border.
        /// </summary>
        public int BorderSize { get; set; }

        /// <summary>
        /// The value of the widget.
        /// </summary>
        public string Value { get; set; }

        /// <summary>
        /// How should the position scale with the parent.
        /// </summary>
        public XAlignment XAlignment { get; set; }

        /// <summary>
        /// How should the position scale with the parent.
        /// </summary>
        public YAlignment YAlignment { get; set; }

        /// <summary>
        /// Should the width be in pixels or percent.
        /// </summary>
        public Measure WidthMeasure { get; set; }

        /// <summary>
        /// Should the height be in pixels or percent.
        /// </summary>
        public Measure HeightMeasure { get; set; }

        /// <summary>
        /// Get the measure of the widgets x-axis.
        /// </summary>
        public Measure XMeasure { get; set; }

        /// <summary>
        /// Get the measure of the widgets y-axis.
        /// </summary>
        public Measure YMeasure { get; set; }

        /// <summary>
        /// The X position of the widget relative to it's parent.
        /// </summary>
        public int X { get; set; }

        /// <summary>
        /// The Y position of the widget relative to it's parent.
        /// </summary>
        public int Y { get; set; }

        /// <summary>
        /// The width of the widget.
        /// </summary>
        public int Width { get; set; }

        /// <summary>
        /// The height of the widget.
        /// </summary>
        public int Height { get; set; }

        /// <summary>
        /// The text that will be displayed if the widget is highlighted.
        /// </summary>
        public string Tooltip { get; set; }

        /// <summary>
        /// The name of the style class use.
        /// </summary>
        public string Class { get; internal set; }

        /// <summary>
        /// The unique name of the widget.
        /// </summary>
        public string Name { get; internal set; }

        /// <summary>
        /// The childs of the widget.
        /// </summary>
        public Widget[] Childs { get; internal set; }

        /// <summary>
        /// The Parent of the widget, null if the widget has no parent.
        /// </summary>
        public Widget Parent { get; internal set; }

        /// <summary>
        /// The widgets tag, often containing information.
        /// </summary>
        public object Tag { get; set; }

        /// <summary>
        /// Allow the WidgetCompiler to access the style.
        /// </summary>
        internal Style Style 
        { 
            get { return style; }
            set { style = value; }
        }
        #endregion

        #region initialization
        public Widget()
        {
            style = new Style();
        }
        #endregion

        #region methods
        public string ToXml()
        {
            throw new NotImplementedException();
        }

        public XElement ToXElement()
        {
            throw new NotImplementedException();
        }

        protected virtual void SaturateFromStyle()
        {
            Measure measure = Measure.Pixels;

            #region actions
            Action<string> parseColor = s =>
                {
                    if(style.IsAttributeDefined(s))
                        style[s] = DataExtractor.DColorParse(style[s]);
                    else
                        style[s] = Color.White;
                };

            Action<string> parseFont = s =>
            {
                if (style.IsAttributeDefined(s))
                    style[s] = DataExtractor.DFontParse(style[s]);
                else
                    style[s] = DataExtractor.DFontParse("");
            };

            Action<string> parseTexture = s =>
            {
                if (style.IsAttributeDefined(s))
                    style[s] = DataExtractor.DTextureParse(style[s]);
                else
                    style[s] = DataExtractor.DTextureParse("");
            };
            #endregion

            #region measures
            //X
            X = DataExtractor.TrySetFromStyle<int>("x", style, s =>
                DataExtractor.DIntParse(s, out measure), 0);
            XMeasure = measure;
            measure = Measure.Pixels;
            //Y
            Y = DataExtractor.TrySetFromStyle<int>("y", style, s =>
                DataExtractor.DIntParse(s, out measure), 0);
            YMeasure = measure;
            measure = Measure.Pixels;
            //Width
            Width = DataExtractor.TrySetFromStyle<int>("width", style, s =>
                DataExtractor.DIntParse(s, out measure), 0);
            WidthMeasure = measure;
            measure = Measure.Pixels;
            //height
            Height = DataExtractor.TrySetFromStyle<int>("height", style, s =>
                DataExtractor.DIntParse(s, out measure), 0);
            HeightMeasure = measure;
            measure = Measure.Pixels;

            BorderSize = DataExtractor.TrySetFromStyle<int>("border.size", style,
                s => DataExtractor.DIntParse(s, out measure), 0);
            #endregion

            parseFont("font");
            parseColor("font.color");
            parseTexture("texture");
            parseColor("border.color");
            parseColor("background.color");
            parseColor("foreground.color");
            
        }

        /// <summary>
        /// Handle all the attributes retrived from the widget element
        /// that created this instance.
        /// </summary>
        /// <param name="attributes"></param>
        protected virtual void AttributeParseing(
            Dictionary<string, string> attributes,
            string value)
        {
            Value = value;

            Name = DataExtractor.TrySetFromAttribute("name", attributes);
            Class = DataExtractor.TrySetFromAttribute("class", attributes);
            Tooltip = DataExtractor.TrySetFromAttribute("tooltip", attributes);
        }

        /// <summary>
        /// Let the widget compiler call the saturator that 
        /// set all the widgets data.
        /// </summary>
        /// <param name="attributes"></param>
        /// <param name="value"></param>
        /// <param name="style"></param>
        internal void Saturate(Dictionary<string, string> attributes, 
                                string value, Style style)
        {
            AttributeParseing(attributes, value);
            this.style = style;
            SaturateFromStyle();
        }
        #endregion

        #region static methods
        /// <summary>
        /// Parse a xml widget element string into a widget.
        /// </summary>
        /// <param name="element">The xml string.</param>
        /// <returns>A Widget instance.</returns>
        public static Widget Parse(string element)
        {
            return DataExtractor.WidgetParse(element);
        }

        /// <summary>
        /// Parse a xml widget element into a widget.
        /// </summary>
        /// <param name="element">
        /// A XElement containing a
        /// widget xml element.
        /// </param>
        /// <returns>A Widget instance.</returns>
        public static Widget Parse(XElement element)
        {
            return DataExtractor.WidgetParse(element);
        }
        #endregion
    }
}
